import * as _ from 'lodash';

import { JobStatus } from './type';
import { SimulationJob } from './simulationJob';
import { logger, AtLeastOne } from '../../../common';

export type QueryPredicate = (job: SimulationJob) => boolean;
export class SimulationJobManager {

  private static _instance: SimulationJobManager;

  public static get Instance(): SimulationJobManager {
    if (!this._instance) { this._instance = new SimulationJobManager(); }
    return this._instance;
  }

  private constructor() { }

  private simulationJobs: { [jobId: string]: SimulationJob} = {};

  jobExist(jobId: string): boolean {
    return _.has(this.simulationJobs, jobId);
    // return !_.isEmpty(this.getById(jobId));
  }

  add(simJob: SimulationJob) {
    const jobId = simJob.id;
    if (!this.simulationJobs[jobId]) {
      this.simulationJobs[jobId] = simJob;
    }
  }

  getAll() {
    return Object.values(this.simulationJobs);
  }

  getById(jobId: string) {
    return this.simulationJobs[jobId];
  }

  delete(jobId: string) {
    delete this.simulationJobs[jobId];
  }

  find(query: QueryPredicate) {
    const jobs = this.getAll();
    return _.filter(jobs, query);
  }

  findRunningJobsBy(product: string) {
    return this.find((job) => {
      return job.product === product && job.status === JobStatus.Runing;
    });
  }

  /**
   *  全量更新
   */
  update(simJob: SimulationJob) {
    const jobId = simJob.id;
    if (jobId) {
      this.simulationJobs[simJob.id] = simJob;
    }
  }

  public updateJobStatus(jobId: string, status: JobStatus) {
    const simulationJob = this.getById(jobId);
    const oldStatus = simulationJob.status;
    simulationJob.status = status;
    logger.debug(`🍺 ==> update simulation job(jobId=${jobId}) status (From ${oldStatus} to ${status})`);
    this.update(simulationJob);
  }

  getJobStatus(jobId: string) {
    return this.getById(jobId)?.status;
  }

  updateBySelective(jobId: string, updatedAttributes: AtLeastOne<Omit<SimulationJob, 'jobId'>>) {
    const simJob = this.getById(jobId);
    if (!_.isEmpty(simJob)) {
      const mergedJob = _.merge(simJob, updatedAttributes);
      this.simulationJobs[mergedJob.id] = mergedJob;
    }
  }
}